/*******************************************************************
** This code is part of Breakout.
**
** Breakout is free software: you can redistribute it and/or modify
** it under the terms of the CC BY 4.0 license as published by
** Creative Commons, either version 4 of the License, or (at your
** option) any later version.
******************************************************************/
#include "resourcemanager.h"

#include <iostream>
#include <sstream>
#include <fstream>

#include <stb_image/stb_image_no_warnings.h>

// Instantiate static variables
std::map<std::string, Texture2D>    ResourceManager::Textures;
std::map<std::string, ShaderProgram>       ResourceManager::Shaders;


ShaderProgram ResourceManager::LoadShader(const GLchar *vShaderFile, const GLchar *fShaderFile, const GLchar *gShaderFile, std::string name)
{
    Shaders[name] = loadShaderFromFile(vShaderFile, fShaderFile, gShaderFile);
    return Shaders[name];
}

ShaderProgram ResourceManager::GetShader(std::string name)
{
    return Shaders[name];
}

Texture2D ResourceManager::LoadTexture(const GLchar *file, GLboolean alpha, std::string name)
{
    Textures[name] = loadTextureFromFile(file, alpha);
    return Textures[name];
}

Texture2D ResourceManager::GetTexture(std::string name)
{
    return Textures[name];
}

void ResourceManager::Clear()
{
    // (Properly) delete all shaders	
    for (auto iter : Shaders)
        glDeleteProgram(iter.second.ID);
    // (Properly) delete all textures
    for (auto iter : Textures)
        glDeleteTextures(1, &iter.second.ID);
}

ShaderProgram ResourceManager::loadShaderFromFile(const GLchar *vShaderFile, const GLchar *fShaderFile, const GLchar *gShaderFile)
{
    // 1. Retrieve the vertex/fragment source code from filePath
    // std::string vertexCode;
    // std::string fragmentCode;
    // std::string geometryCode;
    // try
    // {
    //     // Open files
    //     std::ifstream vertexShaderFile(vShaderFile);
    //     std::ifstream fragmentShaderFile(fShaderFile);
    //     std::stringstream vShaderStream, fShaderStream;
    //     // Read file's buffer contents into streams
    //     vShaderStream << vertexShaderFile.rdbuf();
    //     fShaderStream << fragmentShaderFile.rdbuf();
    //     // close file handlers
    //     vertexShaderFile.close();
    //     fragmentShaderFile.close();
    //     // Convert stream into string
    //     vertexCode = vShaderStream.str();
    //     fragmentCode = fShaderStream.str();
    //     // If geometry shader path is present, also load a geometry shader
    //     if (gShaderFile != nullptr)
    //     {
    //         std::ifstream geometryShaderFile(gShaderFile);
    //         std::stringstream gShaderStream;
    //         gShaderStream << geometryShaderFile.rdbuf();
    //         geometryShaderFile.close();
    //         geometryCode = gShaderStream.str();
    //     }
    // }
    // catch (std::exception e)
    // {
    //     std::cout << "ERROR::SHADER: Failed to read shader files" << std::endl;
    // }
    // const GLchar *vShaderCode = vertexCode.c_str();
    // const GLchar *fShaderCode = fragmentCode.c_str();
    // const GLchar *gShaderCode = geometryCode.c_str();
    // 2. Now create shader object from source code
    ShaderProgram shader;
    shader.compileProgram(vShaderFile, fShaderFile);
    // printf("Shader ID:%d\n",shader.ID);
    return shader;
}

Texture2D ResourceManager::loadTextureFromFile(const GLchar *file, GLboolean alpha)
{
    // Create Texture object
    Texture2D texture;
    if (alpha)
    {
        texture.Internal_Format = GL_RGBA;
        texture.Image_Format = GL_RGBA;
    }
    // Load image
    int width, height, nrComponents;
    unsigned char* image = stbi_load(file, &width, &height, &nrComponents, texture.Image_Format == GL_RGBA ? STBI_rgb_alpha : STBI_rgb);
    // Now generate texture
    texture.Generate(width, height, image);
    // And finally free image data
    stbi_image_free(image);
    return texture;
}